package com.orangecy.loglevel;


import com.orangecy.common.exception.OrangeCyException;
import com.orangecy.common.result.PlainResult;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;


/**
 * @Author : orangeCy
 * @Time : 2021/9/29
 * @desc : 猎豹养成产品源码
 *
 * <pre>
 *      - 类如业务需要感知错误报警，error日志，如果是消息驱动 且重试
 *      - 类如业务需要感知错误报警 限流日志，打印warn日志 且重试
 *      - 类如业务可以无感知的错误码，打印一行info日志，且无需重试。
 * </pre>
 */
@Component
@Slf4j
public class LogLevelUtils {

    @Autowired
    private Object apolloEventConfig;

    private static LogLevelUtils logUtils;

    private static final String RETRY = "_retry";


    @PostConstruct
    public void init() {
        logUtils = this;
        logUtils.apolloEventConfig = this.apolloEventConfig;
    }

    /**
     * 是否需要忽略
     *
     * @param code
     * @return true:可忽略 false:不可忽略
     */
    private static boolean isNeedIgnore(Integer code, List<String> ignoreCodes) {

        String retryCode = code + RETRY;

        return ignoreCodes.contains(String.valueOf(code)) || ignoreCodes.contains(retryCode);
    }

    /**
     * 是否需要重试
     *
     * @param code
     * @return true:需要 false:不需要
     */
    private static boolean isNeedRetry(Integer code, List<String> ignoreCodes) {

        String retryCode = code + RETRY;

        return ignoreCodes.contains(retryCode);
    }

    /**
     * 是否能直接跳过 对业务无影响
     * x
     *
     * @param code
     * @return true:可以，false:不可以
     */
    private static boolean canSkip(Integer code, List<String> ignoreCodes) {
        return ignoreCodes.contains(String.valueOf(code));
    }

    private static List<String> getIgnoreCodes() {
        try {
            //从apollo获取错误码 logUtils.apolloEventConfig.ignoreErrorCode
            List<String> ignoreErrorCode = new ArrayList<>();
            if (CollectionUtils.isEmpty(ignoreErrorCode)) {
                return new ArrayList<>();
            }
            return ignoreErrorCode;

        } catch (Exception ex) {
            return new ArrayList<>();
        }
    }

    /**
     * error日志降级 工具方法
     *
     * @param log
     * @param apiDesc api方法描述
     * @param result  结果
     * @param params  入参
     */
    public static void error(Logger log, String apiDesc, PlainResult result, Object... params) {
        int errorCode = result.getCode();
        List<String> ignoreCodes = LogLevelUtils.getIgnoreCodes();

        LogData builder = LogData.builder().desc(apiDesc);
        for (Object param : params) {
            builder.param(param);
        }
        String msg = builder.result(result).toString();

        if (!LogLevelUtils.isNeedIgnore(errorCode, ignoreCodes)) {
            log.error(String.format("[error] logData :%s", msg));
            throw new OrangeCyException(String.valueOf(result.getCode()), result.getMsg());
        }
        if (LogLevelUtils.isNeedRetry(errorCode, ignoreCodes)) {
            //类似限流错误码
            log.warn(String.format("[warn] logData :%s", msg));
            throw new OrangeCyException(String.valueOf(result.getCode()), result.getMsg());
        }
        if (LogLevelUtils.canSkip(errorCode, ignoreCodes)) {
            log.info(String.format("[info] logData :%s", msg));
        }
    }
}